package com.jishuo.nontax.bfc.service;

import com.github.pagehelper.PageHelper;
import com.jishuo.base.bean.BaseResult;
import com.jishuo.base.bean.ErrorCodeEnum;
import com.jishuo.base.bean.Pagination;
import com.jishuo.base.config.NonTaxConfig;
import com.jishuo.base.service.SequenceService;
import com.jishuo.base.util.CommonUtil;
import com.jishuo.base.util.GTimeUtil;
import com.jishuo.nontax.bean.bank.EticketNum;
import com.jishuo.nontax.bean.bank.EticketNumNew;
import com.jishuo.nontax.bean.bank.OnlineOrder;
import com.jishuo.nontax.bean.message.SetEticketNum;
import com.jishuo.nontax.bean.message.SetEticketNumBackOut;
import com.jishuo.nontax.bean.message.SetEticketNumBackOutBills;
import com.jishuo.nontax.bean.message.SetEticketNumBills;
import com.jishuo.nontax.bean.vo.BankVO;
import com.jishuo.nontax.bean.vo.EticketNumVO;
import com.jishuo.nontax.bfc.dao.BankMapper;
import com.jishuo.nontax.bfc.dao.EticketNumMapper;
import com.jishuo.nontax.bfc.pzk.PzkService;
import com.jishuo.nontax.bfc.tlq.MessageFactory;
import com.jishuo.nontax.bfc.tlq.MessageService;
import com.jishuo.nontax.util.BillStateUtil;
import com.jishuo.nontax.util.PzkUtils;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.StringReader;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 电子缴费业务处理
 *
 * @auther dinggaofei
 * @Date 2022/12/22 8:44
 */
@Service
public class EticketNumService {
    private static Logger logger = LoggerFactory.getLogger(EticketNumService.class);

    @Resource
    private NonTaxConfig nonTaxConfig;
    @Resource
    private SequenceService sequenceService;
    @Resource
    private MessageService messageService;
    @Resource
    private EticketNumMapper eticketNumMapper;
    @Resource
    private BankMapper bankMapper;
    @Resource
    private OnlineOrderService onlineOrderService;
    @Resource
    private PzkService pzkService;
    @Resource
    private PzkUtils pzkUtils;

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 根据缴费码从财政查询缴费单据
     *
     * @param billNum 缴费码
     * @return 票据xml报文，EticketNum
     */
    public BaseResult getEticketNum(String billNum) {
        BaseResult ret = this.getEticketNumVO(billNum);
        if (ret.isSuccess()) {
            try {
                //xml解析器
                Serializer serializer = new Persister();
                //xml转换器
                StringWriter sw = new StringWriter();
                EticketNum eticketNum = ((EticketNumVO)ret.getData()).getEticketNum();
                serializer.write(eticketNum, sw);
                ret.setData(sw.toString());
            } catch (Exception e) {
                logger.info("获取电子缴款书失败，billnum=" + billNum, e);
                return new BaseResult(ErrorCodeEnum.SYS_ERR);
            }
        }
        return ret;
    }

    /**
     * 根据缴费码从财政查询缴费单据
     *
     * @param billNum 缴费码
     * @return 票据xml报文，EticketNumNew
     */
    public BaseResult getNewEticketNum(String billNum) {
        BaseResult ret = this.getEticketNumVO(billNum);
        if (ret.isSuccess()) {
            try {
                //xml解析器
                Serializer serializer = new Persister();
                //xml转换器
                StringWriter sw = new StringWriter();
                EticketNumNew eticketNum = ((EticketNumVO)ret.getData()).getEticketNumNew();
                serializer.write(eticketNum, sw);
                ret.setData(sw.toString());
            } catch (Exception e) {
                logger.info("获取电子缴款书失败，billnum=" + billNum, e);
                return new BaseResult(ErrorCodeEnum.SYS_ERR);
            }
        }
        return ret;
    }

    /**
     * 根据缴费码从财政查询缴费单据
     *
     * @param billNum 缴费码
     * @return EticketNumVO对象
     */
    public BaseResult getEticketNumVO(String billNum) {
        logger.info("请求获取电子交款号:" + billNum);

        // 根据缴费码从本地获取票据
        EticketNumVO bill = eticketNumMapper.findEticketNumByBill(billNum);

        try {
            BaseResult ret = new BaseResult();

            // 已缴费的直接返回
            if (bill != null && (bill.getBillstate() == 3 || bill.getIsbankaffirm() == 1)) {
                bill.setBillstate(3);
                ret.setData(bill);
                ret.setMsgExt(BillStateUtil.getBillState(BillStateUtil.BillType_EticketNum, bill.getBillstate()));
                return ret;
            }

            // 更新messageid
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");
            if (bill == null) {
                long billid = sequenceService.getNextSeq("FSETICKETNUMSEQ");
                bill = new EticketNumVO();
                bill.setBillid(billid);
                bill.setBillnum(billNum);
                bill.setMessageid(messageid);
                eticketNumMapper.insertBlankBill(bill);
            } else {
                bill.setMessageid(messageid);
                eticketNumMapper.updateMsgInfo(bill);
            }

            // 从财政查询
            boolean suc = messageService.sendAndRecvMessage("GETETICKETNUM", messageid, MessageFactory.getEicketNum(billNum), "2.4");
            if (suc) {
                bill = eticketNumMapper.findEticketNumByBill(billNum);
                ret.setData(bill);
                ret.setMsgExt(BillStateUtil.getBillState(BillStateUtil.BillType_EticketNum, bill.getBillstate()));
                return ret;
            }
            return new BaseResult(ErrorCodeEnum.BILL_GET_TIMEOUT);
        } catch (Exception ex) {
            logger.info("获取电子缴款书失败，billnum=" + billNum, ex);
            return new BaseResult(ErrorCodeEnum.SYS_ERR);
        }
    }

    /** 缴费，发送财政 */
    public BaseResult setEticketNumDeposit(String billnum, String paybankdt, String bankaffirm, String bankstation, int paywayid, String paychnl, String payeraccount, Map<String, Object> ext) {
        // 参数检查
        String retMsg = "";
        if (billnum == null || "".equals(billnum)) {
            retMsg += "票号未填写；";
        } else if (paybankdt == null || "".equals(paybankdt)) {
            retMsg += "缴费时间未填写；";
        } else if (bankaffirm == null || "".equals(bankaffirm)) {
            retMsg += "交易流水号未填写；";
        } else if (paywayid < 1) {
            retMsg += "付款方式未填写；";
        }
        if (!"".equals(retMsg)) {
            logger.info("缴费参数错误。" + retMsg);
            return new BaseResult(ErrorCodeEnum.PARAM_ERR);
        }

        EticketNumVO eticketNum = eticketNumMapper.findEticketNumByBill(billnum);
        if (eticketNum == null) {
            logger.info("电子缴款号不存在（票号：" + billnum + "）");
            return new BaseResult(ErrorCodeEnum.BILL_NOT_FOUND);
        }

        // 判断是否已缴费
        if (eticketNum.getIsbankaffirm() == 1) {
            // 日期一致的允许二次提交
            if (!paybankdt.substring(0, 10).equals(eticketNum.getPaybankdt().substring(0, 10))) return new BaseResult(ErrorCodeEnum.BILL_PAYED);
        } else if (eticketNum.getBillstate() == 3) {
            return new BaseResult(ErrorCodeEnum.BILL_PAYED);
        }

        // 处理扩展数据
        if (ext != null) {
            // TODO: 2023/1/31
        }

        // 更新业务表
        eticketNum.setBankaffirm(bankaffirm);
        eticketNum.setPaybankdt(paybankdt);
        eticketNum.setBankstation(bankstation);
        eticketNum.setPayway(paywayid);
        eticketNum.setIsbankaffirm(1);
        eticketNum.setSendtime(sdf.format(new Date()));
        int n = eticketNumMapper.updateBillPay(eticketNum);
        OnlineOrder oo = new OnlineOrder();
        oo.setBillnum(billnum);
        oo.setAmt(eticketNum.getAmt().toPlainString());
        oo.setBankaffirm(bankaffirm);
        oo.setBilltype(1);
        oo.setPaybankdt(paybankdt);
        oo.setPaychnl(paychnl);
        oo.setPayee(eticketNum.getPayee());
        oo.setPayeeaccount(eticketNum.getPayeeaccount());
        oo.setPayer(eticketNum.getPayer());
        oo.setPayeraccount(payeraccount);
        oo.setPaytype(1);
        onlineOrderService.saveOnlineOrder(oo);
        if (n < 1) {
            return new BaseResult(ErrorCodeEnum.DB_ERR.getCode(), "保存缴款书失败（" + billnum + "）");
        }

        // 发送财政
        List<EticketNumVO> list = new ArrayList<>();
        list.add(eticketNum);
        this.sendEticketNum(list);

        // 写凭证
        pzkService.savePzmsg("SETETICKETPZK", pzkUtils.getEticketNum(eticketNum));

        return new BaseResult();
    }

    /**
     * 财政返回票据，入库
     * @param data 财政报文
     * @param billstate 票据状态
     * @param sn 消息sn
     */
    public void setEticketNum(String data, int billstate, String sn) {
        if (billstate == 1) {
            try {
                //xml解析器
                Serializer serializer = new Persister();
                //返回缴款书对象
                SetEticketNumBills setEticketNumbills = serializer.read(SetEticketNumBills.class, new StringReader(data));

                if (setEticketNumbills != null && setEticketNumbills.getSetnum() != null) {
                    for (SetEticketNum setEticketNum : setEticketNumbills.getSetnum()) {
                        if (setEticketNum != null) {
                            EticketNumVO vo = new EticketNumVO(setEticketNum);
                            BankVO bankVO = bankMapper.findBankVO(vo.getPayeeaccount());
                            vo.setBillstate(billstate);
                            vo.setIssend(2);
                            vo.setBankid(bankVO.getBankid().intValue());
                            if (eticketNumMapper.saveSetEticketNum(vo) <= 0) {
                                break;
                            }
                        }
                    }
                }
            } catch (Exception e) {
                logger.info("解析缴款书失败。sn=" + sn, e);
            }
        } else if (billstate > 1) {
            long messageid = Long.parseLong(sn.substring(sn.indexOf("-") + 1));
            eticketNumMapper.updateEticketNumBillState(messageid, billstate);
        }
    }

    /**  页面 获取电子票列表数据 */
    public List<EticketNumVO> listEticketNum(EticketNumVO eticketNumVO, Pagination pagination) {

        if (pagination.getRows() > 0) PageHelper.startPage(pagination.getPage(), pagination.getRows());
        List<EticketNumVO> eticketNumVOS = this.eticketNumMapper.listEticketNum(eticketNumVO);
        return eticketNumVOS;
    }

    /** 发送财政 */
    private BaseResult sendEticketNum(List<EticketNumVO> voList) {
        // 发送财政
        try {
            Object obj = MessageFactory.setEticketNumDeposit(voList);
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");
            messageService.sendMessage("SETETICKETNUMDEPOSIT", messageid, obj, "2.6");
            return new BaseResult();
        } catch (Exception e) {
            logger.info("发送电子缴款错误。", e);
            return new BaseResult(ErrorCodeEnum.UNKNOWN_ERR.getCode(), "发送电子缴款错误：" + e.toString());
        }
    }

    /** 页面，补发财政 */
    public BaseResult sendEticketNum(String billids) {
        long[] ids = CommonUtil.getIdsLong(billids);
        if (ids.length == 0) return new BaseResult(ErrorCodeEnum.PARAM_ERR);
        List<EticketNumVO> list = eticketNumMapper.findEticketNumByIsbankaffirm(ids);
        if (list.size() == 0) return new BaseResult();

        return this.sendEticketNum(list);
    }

    /**
     * 冲销
     */
    public BaseResult cleanEticketNum(String billids, String usercode) {
        String errinfo = "";
        try {
            long[] ids = CommonUtil.getIdsLong(billids);
            if (ids.length == 0) return new BaseResult(ErrorCodeEnum.PARAM_ERR);
            List<EticketNumVO> list = eticketNumMapper.findEticketNumByIsbankaffirm(ids);
            Calendar cal = Calendar.getInstance();
            String cxTime = sdf.format(cal.getTime());
            cal.add(Calendar.MINUTE, 0 - nonTaxConfig.CxTime);
            String chkTime = sdf.format(cal.getTime());

            for (EticketNumVO vo : list) {
                if (vo.getSendtime() == null || vo.getSendtime().length() == 0 || chkTime.compareTo(vo.getSendtime()) < 0) {
                    setEticketNumBackOut(cxTime, usercode, vo);
                    eticketNumMapper.updateIsbankaffirm(vo.getBillid());
                } else {
                    errinfo += vo.getBillnum() + ",";
                }
            }

            if (!errinfo.equals("")) {
                errinfo += "超时冲销失败,其他单据冲销成功!";
                return new BaseResult(ErrorCodeEnum.CUSTOM_ERR.getCode(), errinfo);
            } else {
                errinfo = "冲销成功";
                return new BaseResult(ErrorCodeEnum.SUCCESS.getCode(), errinfo);
            }
        } catch (Exception e) {
            return new BaseResult(ErrorCodeEnum.UNKNOWN_ERR);
        }
    }

    /**
     * 冲销单据
     * @param backoutdt 冲销时间
     * @param backoutname 操作用户
     * @param eticketNumVO 单据
     * @return
     */
    private BaseResult setEticketNumBackOut(String backoutdt, String backoutname, EticketNumVO eticketNumVO) {
        try {
            SetEticketNumBackOutBills setEticketNumBackOutBills = new SetEticketNumBackOutBills();
            List<SetEticketNumBackOut> list = new ArrayList<>();
            SetEticketNumBackOut setEticketNumBackOut = eticketNumVO.getSetEticketNumBackOut();
            setEticketNumBackOut.setBackoutdt(backoutdt);
            setEticketNumBackOut.setRemark("冲销");
            setEticketNumBackOut.setBackoutname(backoutname);
            list.add(setEticketNumBackOut);
            setEticketNumBackOutBills.setSetout(list);
            long messageid = sequenceService.getNextSeq("ELEMESSAGESEQ");
            //发送到财政
            messageService.sendMessage("SETETICKETNUMBACKOUT", messageid, setEticketNumBackOutBills, "2.7");
            // 写凭证
            pzkService.savePzmsgOut(BillStateUtil.BillType_EticketNum, eticketNumVO.getBillnum(), eticketNumVO.getBankaffirm());
            return new BaseResult();
        } catch (Exception e) {
            logger.info("处理获取缴款书失败：" + e.toString());
            return new BaseResult(ErrorCodeEnum.UNKNOWN_ERR);
        }
    }

    /**
     * 电子缴费收款，view页面提交
     *
     * @param eticketNumVO
     * @return
     */
    public BaseResult eticketnumpayview(EticketNumVO eticketNumVO) {
        try {
            String paybankdt = GTimeUtil.getDateTimeMark();
            eticketNumVO.setPaybankdt(paybankdt);
           return setEticketNumDeposit(eticketNumVO.getBillnum(), eticketNumVO.getPaybankdt(), eticketNumVO.getBankaffirm(), eticketNumVO.getBankstation(), eticketNumVO.getPayway(), "", "", null);
        } catch (Exception e) {
            logger.info("缴费异常。", e);
            return new BaseResult(ErrorCodeEnum.CUSTOM_ERR.getCode(), "缴费异常");
        }
    }
}
